<?php
	
	namespace Aspic\Session;
	
	use Aspic as A;
	use Aspic\File\File;
	
	class FileSession extends AbstractSession {
		const SESSIONS_DATA_FILE_NAME = 'sessions.data';
	
		protected $storageDir;
		
		public function __construct($storageDir = '.', $lifeTime = 86400, array $options = array()) {
			// because in destruct the CU (current directory is not the same as in others methods see php doc)
			
			$this->storageDir = realpath($storageDir);
			parent::__construct($lifeTime, $options);
		}
		
		############### READ / WRITE METHODS ##########################
		
		protected function saveSession($id, $data) {
			$fileCts = array(
				$data['creationTime'], 
				$data['ip'], 
				$data['navigator'], 
				$data['acceptLanguages'], 
				rawurlencode(serialize($data['data']))
			);
			
			
			return File::putContents($this->getSessionPath($id), implode("\n", $fileCts), LOCK_EX);
		}
		
		protected function getSessionData($id) {
			$path = $this->getSessionPath($id);
			
			if(is_file($path)) {				
				$sessFileLines = File::getLines($path);
					
				if(count($sessFileLines) > 0) {
					$creationTime = (int)$sessFileLines[0];
					$ip = $sessFileLines[1];
					$navigator = $sessFileLines[2];
					$langs = $sessFileLines[3];
					$vars = unserialize(rawurldecode($sessFileLines[4]));
					
					// return array($creationTime, $ip, $navigator, $langs, $vars);
					return array(
						'creationTime' => $creationTime, 
						'ip' => $ip, 
						'navigator' => $navigator, 
						'acceptLanguages' => $langs, 
						'data' => $vars
					);
				}
				else {
					throw new A\Exception('Session file is empty (id: '.$id.') '.$_SERVER['REQUEST_URI'].'');
				}
			}
			else {
				throw new A\Exception('Session file with id: "'.$id.'" does not exist');
			}
		}
		
		/**
		* Remove a session
		*/
		protected function removeSession($id) {
			unlink($this->getSessionPath($id));
		}
		
		protected function getAllSessions() {
			$sessionsFiles = glob($this->storageDir.'/*.session');
			
			return $sessionsFiles;
		}
		
		
		/**
		* Check if it is time to clean session folder (or other storage way)
		*/
		protected function checkClean() {
			if(!is_null($this->cleanInterval)) {
				if(!is_file($this->storageDir.'/'.static::SESSIONS_DATA_FILE_NAME)) {
					File::putContents($this->storageDir.'/'.static::SESSIONS_DATA_FILE_NAME, time());
				}
				else {
					$lastClean = (int)File::getContents($this->storageDir.'/'.static::SESSIONS_DATA_FILE_NAME);
					
					if(($lastClean + $this->cleanInterval) <= time()) {
					
						File::putContents($this->storageDir.'/'.static::SESSIONS_DATA_FILE_NAME, time());
						$this->clean();
					}
				}
			}
		}
		
		/**
		* Remove session (file) that have expire
		*/
		protected function clean() {
			$sessionsFiles = $this->getAllSessions();

			foreach($sessionsFiles as $sessionFilePath) {
				$id = substr($sessionFilePath, strrpos($sessionFilePath,'/') + 1);
				$id = substr($id, 0, strpos($id, '.session'));

				if($this->hasSessionExpire($id)) {
					$this->removeSession($id);
				}
			}
		}
		
		protected function sessionIdExists($id) {
			return is_file($this->getSessionPath($id));
		}
		
		protected function getSessionPath($id) {
			return $this->storageDir.'/'.str_replace('..', '', $id).'.session';
		}
		
	}
	
?>